package tomcat.connector;

import tomcat.processor.StaticProcessor;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.*;
import java.util.Set;

public class NioConnector implements Runnable{
    private static final int DEFAULT_PORT = 8888;

    private ServerSocketChannel server;

    private int port;

    private Selector selector;

    public NioConnector() {
        this(DEFAULT_PORT);
    }

    public NioConnector(int port) {
        this.port = port;
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }



    private void close(Closeable closable) {
        if (closable != null) {
            try {
                closable.close();
                System.out.println("关闭" + closable);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        try {
            // 创建 ServerSocketChannel
            server = ServerSocketChannel.open();
            // ServerSocketChannel 非阻塞调用状态
            server.configureBlocking(false);
            // 通道关联的ServerSocket 绑定端口
            server.socket().bind(new InetSocketAddress(port));

            // 监听所有事件 及 通道状态变化
            selector = Selector.open();
            server.register(selector, SelectionKey.OP_ACCEPT); // 通过SelectionKey 对象 获取发生事件所有信息
            System.out.println("启动Server， 监听端口：" + port + "...");

            while (true) {
                // 本身阻塞,上面可能注册多个通道,调用select()时, 所有通道都没有 selector监听事件发生, select()函数不会返回,一直阻塞
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey key : selectionKeys) {
                    // 处理被触发的事件
                    handles(key);
                }
                selectionKeys.clear();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(selector);
        }
    }

    private void handles(SelectionKey key) throws IOException {
        // Accept
        if(key.isAcceptable()){
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel client = server.accept();
            client.configureBlocking(false);
            client.register(selector, SelectionKey.OP_READ);
        } else { // READ
            SocketChannel client= (SocketChannel) key.channel();
            // 这条socketChannel 不被 selector 所轮询
            key.cancel();
            client.configureBlocking(true);  // 再变回阻塞模式

            Socket socket = client.socket();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            DynamicRequest request = new DynamicRequest(inputStream);
            request.parse();

            DynamicResponse response = new DynamicResponse(outputStream);
            response.setRequest(request);
            if (request.getUri().startsWith("/servlet")) {
                ServletProcessor processor = new ServletProcessor();
                processor.process(request, response);
            }else {
                StaticProcessor processor = new StaticProcessor();
                processor.process(request, response);
            }

            close(client);

        }

    }
}
